/**
 * @file STL_Serial.h
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief
 * @version 0.1
 * @date 2021-03-25
 *
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 *
 */

#ifndef __STL_SERIAL_H__
#define __STL_SERIAL_H__

#include <string>
#include <stdint.h>
#include <functional>
#include <thread>
#include <mutex>
#include <list>
#include <queue>
#include <memory>
#include <map>
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include "STL_Tools.h"

#define STL_Serial_Buffer_Max 32 * 1024

namespace STL
{
    class STL_Serial
    {
    public:
        typedef enum Status_e
        {
            None,
            Init,
            Working,
            ERROR,
            Over
        } Status;

        /**
         * @brief 奇偶校验  默认 [ 无 ]
         * [ 无 | 奇 | 偶 | 标记 | 空格 ]
         */
        typedef enum Parity_e
        {
            Parity_None = 0, // 无
            Parity_Odd,      // 奇
            Parity_Even,     // 偶
            Parity_Mark,     // 标记
            Parity_Space     // 空格
        } Parity;
        /**
         * @brief 停止位  默认 [ 1 ]
         *  [ 1 | 1.5 | 2 ]
         */
        typedef enum StopBits_e
        {
            StopBits_One = 0,         // 1
            StopBits_OneAndAHalf = 1, // 1.5
            StopBits_Two = 2          // 2
        } StopBits;
        typedef struct SerialConfig_t
        {
            /*
            xshell
            端口号 串口路径
            波特率 默认 115200
            数据位 5,6,7,8 默认 8
            停止位 1,1.5,2 默认 1
            奇偶校验 无,奇,偶,标记，空格 默认 无
            流控制 无, RTS/CTS , XON/XOFF 默认 无
            */
            std::string line = "/dev/ttyUSB0"; // 串口路径
            Parity parity = Parity_None;       // 奇偶校验
            StopBits stopBits = StopBits_One;  // 停止位
            uint32_t baud = 115200;            // 波特率
            // int speed = 115200; //波特率
            std::string carrier_watch = "off";
            std::string handshake = "none";
            std::string flow_control = "none"; // 流控制
            bool robust = true;
            std::string fileType = "bin";
            std::string fileName = "lit";
            int recPack = 1000;
            int sendPack = 1000;
            int window = 5;
            SerialConfig_t(std::string path)
            {
                this->line = path;
            }
            SerialConfig_t(std::string path, uint32_t baud)
            {
                this->line = path;
                this->baud = baud;
            }
        } SerialConfig;
        typedef std::function<void()> ConnectCallback;
        typedef std::function<void()> DisconnectCallback;
        typedef std::function<void(std::shared_ptr<std::string>)> DataCallback;

    public:
        STL_Serial(SerialConfig config);
        ~STL_Serial();
        int openSerial();
        int closeSerial();

    private:
        static void setnonblocking(int sock);

    public:
        void sendData(std::string &data);
        // void sendData(std::string *data)
        // {
        //     sendData(socket, &(*data));
        // };
        void closeSocket();

    public:
        STL_STATUS_CALLBACK(STL_Serial::Status);
        STL_SYNTHESIZE(STL::STL_Serial::ConnectCallback, m_ConnectCallback, ConnectCallback);
        STL_SYNTHESIZE(STL::STL_Serial::DisconnectCallback, m_DisconnectCallback, DisconnectCallback);
        STL_SYNTHESIZE(STL::STL_Serial::DataCallback, m_DataCallback, DataCallback);

    private: // event
        int init(uint32_t const attempts);
        void onData(int socket);
        void onConnect(int socket, std::string ip, uint16_t port);
        void onDisconnect(int socket);

    private:
        SerialConfig m_config;
        int m_serial_fd;
        int m_epoll_fd;

    private:
        bool m_run;
        std::thread m_thread;
        std::mutex m_mutex;
        void serialThread();

    private:
        char *m_buffer[STL_Serial_Buffer_Max]; // 大内存块放到类里，防止频繁开辟空间
    };
} // namespace STL

#endif //__STL_SERIAL_H__